iT邦幫忙

2024 iThome 鐵人賽

DAY 11
0
自我挑戰組

自學vue~點亮Roadmap過程系列 第 11

vue3鍊成術第十一天-生命週期和模板引用(實作)

  • 分享至 

  • xImage
  •  

生命週期和模板引用

目前為止,Vue 為我們處理了所有的 DOM 更新,這要歸功於響應性和聲明式渲染。然而,有時我們也會不可避免地需要手動操作 DOM。

這時我們需要使用模板引用——也就是指向模板中一個 DOM 元素的 ref。我們需要通過這個特殊的 ref 屬性來實現模板引用:

<p ref="pElementRef">hello</p>

我們需要宣告一個同名的 ref:

const pElementRef = ref(null)

注意這個 ref 使用 null 值來初始化。這是因為當 script setup 執行時,DOM 元素還不存在。模板引用 ref 只能在組件掛載後訪問。

要在掛載之後執行代碼,我們可以使用 onMounted() 函數:

import { onMounted } from 'vue'

onMounted(() => {
  // 此時組件已經掛載。
})

這被稱為生命週期鉤子——它允許我們註冊一個在組件的特定生命週期調用的回調函數。還有一些其他的鉤子如 onUpdated 和 onUnmounted。

實作

嘗試添加一個 onMounted 鉤子,然後通過 pElementRef.value 訪問 p,並直接對其執行一些 DOM 操作。(例如修改它的 textContent)。

<script setup>
import { ref } from 'vue'

const pElementRef = ref(null)
</script>

<template>
  <p ref="pElementRef">Hello</p>
</template>

https://ithelp.ithome.com.tw/upload/images/20240924/20169210syruc5ovPQ.png

完成

<script setup>
import { ref, onMounted } from 'vue'

const pElementRef = ref(null)

onMounted(() => {
  pElementRef.value.textContent = 'mounted!'
})
</script>

<template>
  <p ref="pElementRef">Hello</p>
</template>

https://ithelp.ithome.com.tw/upload/images/20240924/20169210cOEIs4q6zj.png

偵聽器

有時我們需要響應性地執行一些“副作用”——例如,當一個數字改變時將其輸出到控制台。我們可以通過偵聽器來實現它:

import { ref, watch } from 'vue'

const count = ref(0)

watch(count, (newCount) => {
  // 沒錯,console.log() 是一個副作用
  console.log(`new count is: ${newCount}`)
})

watch() 可以直接偵聽一個 ref,並且只要 count 的值改變就會觸發回調。watch() 也可以偵聽其他類型的數據源

實作

一個比在控制台輸出更加實際的例子是當 ID 改變時抓取新的數據。下面的例子中就是這樣一個組件。該組件被掛載時,會從模擬 API 中抓取 todo 數據,同時還有一個按鈕可以改變要抓取的 todo 的 ID。現在,嘗試實現一個偵聽器,使得組件能夠在按鈕被點擊時抓取新的 todo 項目。

<script setup>
import { ref } from 'vue'

const todoId = ref(1)
const todoData = ref(null)

async function fetchData() {
  todoData.value = null
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  todoData.value = await res.json()
}

fetchData()
</script>

<template>
  <p>Todo id: {{ todoId }}</p>
  <button @click="todoId++" :disabled="!todoData">Fetch next todo</button>
  <p v-if="!todoData">Loading...</p>
  <pre v-else>{{ todoData }}</pre>
</template>

https://ithelp.ithome.com.tw/upload/images/20240924/20169210KIqPZoYeA0.png

完成

<script setup>
import { ref, watch } from 'vue'

const todoId = ref(1)
const todoData = ref(null)

async function fetchData() {
  todoData.value = null
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId.value}`
  )
  todoData.value = await res.json()
}

fetchData()

watch(todoId, fetchData)
</script>

<template>
  <p>Todo id: {{ todoId }}</p>
  <button @click="todoId++" :disabled="!todoData">Fetch next todo</button>
  <p v-if="!todoData">Loading...</p>
  <pre v-else>{{ todoData }}</pre>
</template>

https://ithelp.ithome.com.tw/upload/images/20240924/20169210DhkbRWDtkU.pnghttps://ithelp.ithome.com.tw/upload/images/20240924/20169210IahG7tJkR9.pnghttps://ithelp.ithome.com.tw/upload/images/20240924/20169210kOyAO5pN0N.pnghttps://ithelp.ithome.com.tw/upload/images/20240924/2016921085dfoC0tSk.png


上一篇
vue3鍊成術第十天-計算屬性(實作)
下一篇
vue3鍊成術第十二天-組件(實作)
系列文
自學vue~點亮Roadmap過程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言